#ifndef _CRY_COMMON_CRY_CHAR_ANIMATION_PARAMS_HDR_
#define _CRY_COMMON_CRY_CHAR_ANIMATION_PARAMS_HDR_


#include <Tarray.h>
#include "ISerialize.h"
#include "crc32.h"


#define MAX_LMG_ANIMS (40)
#define MAX_LMG_DIMENSIONS (4)


// The flags used in the nFlags member.
enum CA_AssetFlags
{
	// Description:
	//		If this is true, then this asset is an additive animation.
	// Summary:
	//		This flags in used in RC as well
	CA_ASSET_ADDITIVE		= 0x001,   
	// Description:
	//		If this is true, then its possible to use this asset with the loop-flag.
	// Summary:
	//		This flags in used in RC as well
	CA_ASSET_CYCLE			= 0x002,    

	// Description:
	//		If this is true, then the asset has valid info data (has been loaded at least once).
	CA_ASSET_LOADED			= 0x004,


	// Description:
	//		If this is true, then the asset is a locomotion group (LMG).
	CA_ASSET_LMG				= 0x008,
	// Description:
	//		If this is true, then the LMG has been processed at loading time.
	CA_ASSET_LMG_VALID	= 0x020,


	// Description:
	//		If this is true, then the asset is a locomotion group (LMG).
	CA_ASSET_PMG				= 0x040,
	// Description:
	//		If this is true, then the LMG has been processed at loading time.
	CA_ASSET_PMG_VALID	= 0x080,

	// 0x100 and 0x200 are used for development and testing

	// Description:
	//		If this is true, then the asset has been processed at loading time.
	CA_ASSET_PROCESSED	= 0x400,
	// Description:
	//		If this true, then the asset is created but not loaded.
	CA_ASSET_CREATED    = 0x800,
	// Description:
	//		If this true, then the asset is already requested for loading.
	CA_ASSET_REQUESTED  =	0x1000,
	// Description:
	//		If this true, then the asset has on-demand loading.
	CA_ASSET_ONDEMAND   = 0x2000,
	// Description:
	//		If this true, then this asset is an AimPose.
	CA_AIMPOSE					= 0x4000,
	// Description:
	//		If this true, then we had an AimPose that we removed from memory.
	CA_AIMPOSE_UNLOADED = 0x8000,
	//
	CA_ASSET_NOT_FOUND  = 0x10000,

	CA_ASSET_TCB        = 0x20000,

	CA_ASSET_BIG_ENDIAN = 0x80000000
	
};




enum CA_AnimationFlags
{

	//-------------------------------------------------------------
	//FLAGS TO HANDLE ANIMATION PLAYBACK
	//-------------------------------------------------------------
	//	All playback flags are exclusive. Only one of them can be enabled for an animation at a time. Order of priotity:
	//	CA_MANUAL_UPDATE, (disables looping and repeat) 
	//	CA_LOOP_ANIMATION, (disables repeat) 
	//	CA_REPEAT_LAST_KEY, 

	// Description:
	//		With this flag the animation is not being updated automatically. The user needs to set the time manually. This is used for steering-wheels and mounted-weapons, where we convert the rotation of an object into animation-keytimes 
	CA_MANUAL_UPDATE			=0x000001, 

	// Description:
	//		Plays an animations in an endless loop till we stop this animation or start a new animation.
	CA_LOOP_ANIMATION			=0x000002, 

	// Description:
	//		Plays an animation once and then repeats the last keyframe. Without this flag we remove the 
	//		animation from the FIFO.  
	CA_REPEAT_LAST_KEY		=0x000004, 


	//-------------------------------------------------------------
	//FLAGS TO HANDLE TRANSITIONS
	//-------------------------------------------------------------

	// Description:
	//		Linear time-warping of animations to align animation with similar properties
	CA_TRANSITION_TIMEWARPING	=0x000008, 

	// Description:
	//		Don't start a transition immediately. Wait till the previous animation is passing a specified key-time
	CA_START_AT_KEYTIME				=0x000010, 

	// Description:
	//		Can be simulated by using the flags "CA_START_AT_KEYTIME" and "CA_REPEAT_LAST_KEY".
	CA_START_AFTER	  				=0x000020, 

	// Description:
	//		When playing an Idel2Move transition, we would like to find the best transition point 
	//		to start a locomotion-animation 
	CA_IDLE2MOVE							=0x000040, 

	// Description:
	//		By default it is not possible to start the same animation twice. In some special cases this is sometimes necessary (e.g. recoil-animations). By enabling this flag we can restart the same animation using the previously described transition-rules. 
	CA_ALLOW_ANIM_RESTART			=0x000080, 




	//-------------------------------------------------------------
	//FLAGS TO HANDLE CONTROLLER USAGE
	//-------------------------------------------------------------
	//enforce 30Hz sampling
	CA_KEYFRAME_SAMPLE_30Hz	    =0x000100, //don't interpolate between 2 keyframes (do only 30hz sampling)
	
	//Don't allow multilayer animations when this flag is set in Layer0
	CA_DISABLE_MULTILAYER       =0x000200,  

	//  When an object is not visible, then we just update the animation but NOT the skeleton. The skeleton will stay in the last updated pose. 
	//  This can can be a problem in some situations, for example when an animation is used to open a door, or when we use skeleton animation 
	//  to move physical objects in the game. A good example is the moving platform in MP to lift up the VTOL and the helicopters).  
	//  The only way to enforce the skeleton-update is to use this flag per animation.      
	CA_FORCE_SKELETON_UPDATE    =0x000400,  

	//-------------------------------------------------------------
	//FLAGS FOR SPECIAL ANIMATION MODES
	//-------------------------------------------------------------
	//	Play this animation only when you're in Track-View.
	CA_TRACK_VIEW_EXCLUSIVE     =	0x000800, 

	// Description:
	// Suppress warnings for flocks.
	CA_SUPPRESS_WARNINGS        =	0x001000, 

	// Description:
	// When playing an locomotion-animation, we would like to find the best transition point to start a Move2Idle.
	CA_MOVE2IDLE								=	0x002000, 

	// Description:
	//		Usually we always update animations, even when the object is not visible. For simple objects (e.g. boids) we want to 
	//		avoid even animation-update. This can lead to an overflow in the FIFO-queue. 
	//		To avoid the overflow, we remove the first animation from the FIFO when there are more then 16 animation in the queue.
	CA_REMOVE_FROM_FIFO	= 0x004000,  

	CA_FULL_ROOT_PRIORITY	= 0x008000,  

	// Description:
	//	An animation with this flag makes sure it's transitioned to. Usually some conditions (anims in the same queue with flags
	// Idle2Move, Move2Idle, StartKeyAfter, StartKeyAtTime, not in memory) can delay the transition, this flag removes them all
	CA_FORCE_TRANSITION_TO_ANIM	= 0x010000,  
};

#define NUM_ANIMATION_USER_DATA_SLOTS 8


struct OldBlendSpace
{
	f32 m_speed;
	Vec2 m_strafe;
	f32 m_turn;
	f32 m_weightshift;
	f32 m_slope;
		
	
	//f32 m_fAllowLeaningSmooth;		// Just for debugging.
	//f32 m_fAllowLeaningSmoothRate;	// Just for debugging.
	uint32 m_updates;							// Just for debugging.
	QuatT m_AnimChar;						 	// Just for debugging.
	
	OldBlendSpace()
	{	
		m_speed=0.0f;
		m_strafe=Vec2(0,0); 
		m_turn=0.0f; 
		m_weightshift=0.0f; 
		m_slope=0.0f;	
		//m_fAllowLeaningSmooth=1.0f;
		//m_fAllowLeaningSmoothRate=1.0f;
		m_updates=0;
		m_AnimChar.SetIdentity();
	};

	/*
	OldBlendSpace( f32 a, f32 b, f32 c, f32 d, f32 e ) 
	{ 
		m_speed		=a; 
		m_strafe	=Vec2(b,c); 
		m_turn		=d; 
		m_slope		=e; 
	};*/

	void Init() 
	{ 
		m_speed		=0; 
		m_strafe	=Vec2(0,0); //forward direction
		m_turn		=0; 
		m_weightshift=0.0f; 
		m_slope		=0; 
	};

} _ALIGN(32);


//--------------------------------------------------------------------------------

enum EWeaponRaisedPose
{
	eWeaponRaisedPose_None				= 0x00,
	eWeaponRaisedPose_Fists				= 0x10,
	eWeaponRaisedPose_Rifle				= 0x20,
	eWeaponRaisedPose_Pistol			= 0x30,
	eWeaponRaisedPose_Rocket			= 0x40,
	eWeaponRaisedPose_MG					= 0x50,

	eWeaponRaisedPose_DualLft			= 0x01,
	eWeaponRaisedPose_DualRgt			= 0x02,

	eWeaponRaisedPose_PistolLft		= eWeaponRaisedPose_Pistol | eWeaponRaisedPose_DualLft,
	eWeaponRaisedPose_PistolRgt		= eWeaponRaisedPose_Pistol | eWeaponRaisedPose_DualRgt,
	eWeaponRaisedPose_PistolBoth	= eWeaponRaisedPose_Pistol | eWeaponRaisedPose_DualLft | eWeaponRaisedPose_DualRgt,
};

//--------------------------------------------------------------------------------

enum EMotionParamID
{
	eMotionParamID_TravelAngle = 0,
	eMotionParamID_TravelDistScale,
	eMotionParamID_TravelSpeed,
	eMotionParamID_TravelDist,
	eMotionParamID_TravelSlope,
	eMotionParamID_WeightShift,
	eMotionParamID_TurnSpeed,
	eMotionParamID_TurnAngle,
	eMotionParamID_Duration,
	eMotionParamID_Curving,
	eMotionParamID_Height,
	eMotionParamID_Scale,

	eMotionParamID_COUNT,
};
extern char* g_szMotionParamID[eMotionParamID_COUNT];

//--------------------------------------------------------------------------------

enum EMotionParamUsage
{
	eMotionParamUsage_None = 0,
	eMotionParamUsage_Interval,
	eMotionParamUsage_Cyclic,
};
extern char* g_szMotionParamUsage[eMotionParamID_COUNT];

//--------------------------------------------------------------------------------

struct MotionParamDesc
{
	// Defined how the parameter value should be used.
	uint32 m_nUsage;
		
	// These are the total limits, including procedural scaling.
	// None: not parameterizable, only a static property (min==max)
	// Interval: Absolute minimum parameter value
	// Cyclic: The calculated parameter is shifted to be within this cyclic range.
	f32 m_fMin;
	f32 m_fMax;
	
	// These are the real limits of the asset.
	f32 m_fMinAsset;
	f32 m_fMaxAsset;
	
	// Parameter value change rate per seconds
	f32 m_fMaxChangeRate;
	f32 m_fAllowProcTurn;

	bool m_bLocked; // =(maxChangeRate == 0.0f)
	
	MotionParamDesc()
	{
		m_nUsage = eMotionParamUsage_None;
		m_bLocked = false;

		m_fMin = 0.0f;
		m_fMax = 0.0f;
		m_fMinAsset = 0.0f;
		m_fMaxAsset = 0.0f;
		m_fMaxChangeRate = 0.0f;
		m_fAllowProcTurn = 0.0f;
	}
} _ALIGN(32);

//--------------------------------------------------------------------------------

struct SAnimMemoryTracker
{
	uint32 m_nMemTracker;
	uint32 m_nAnimsCurrent;
	uint32 m_nAnimsMax;
	uint64 m_nAnimsAdd;
	uint32 m_nAnimsCounter;  
	uint32 m_nGlobalCAFs;  
	uint32 m_nUsedGlobalCAFs;  

	uint32 m_numTCharInstances;
	uint32 m_nTotalCharMememory;
	uint32 m_numTSkinInstances;
	uint32 m_nTotalSkinMememory;  
	uint32 m_numModels;
	uint32 m_nTotalMMememory;

	SAnimMemoryTracker()
	{
		m_nMemTracker=0;
		m_nAnimsCurrent=0;
		m_nAnimsMax=0;
		m_nAnimsAdd=0;
		m_nAnimsCounter=0;  
		m_nGlobalCAFs=0;  
		m_nUsedGlobalCAFs=0;  

		m_numTCharInstances=0;
		m_nTotalCharMememory=0;
		m_numTSkinInstances=0;
		m_nTotalSkinMememory=0;  
		m_numModels=0;
		m_nTotalMMememory=0;
	}

};

//--------------------------------------------------------------------------------

struct LMGCapabilities
{
	uint8 m_bIsValid;			// by default not valid
	uint8 m_bIsLMG;				// 1=LMG / 0=simple asset
	int8 m_bHasStrafingAsset; // 1=has strafing assets, 0=don't have but don't care, -1=don't like at all
	int8 m_bHasTurningAsset;  // 1=has turning assets, 0=don't have but don't care, -1=don't like at all
	int8 m_bHasTurningDistAsset;  // 1=has turning assets, 0=don't have but don't care, -1=don't like at all
	int8 m_bHasSlopeAsset;    // 1=supports uphill/downhill, 0=don't have but don't care, -1=don't like at all
	int8 m_bHasVelocity; // 1=has parameterized speed, 0=don't have but don't care, -1=don't like at all
	int8 m_bHasDistance; // 1=has parameterized speed, 0=don't have but don't care, -1=don't like at all

	int8 m_bHasCurving;

	uint8 m_bpad1;
	uint8 m_bpad2;

	uint32 m_BlendType;	    //blend-type for the LMG

	f32 m_travelAngleChangeRate;
	f32 m_travelSpeedChangeRate;
	f32 m_turnSpeedChangeRate;
	f32 m_curvingChangeRate;

	f32 m_fSlowDuration;			//slow duration of the LMG with these settings
	f32 m_fFastDuration;			//fast duration of the LMG with these settings
	Vec3 m_vMinVelocity;
	Vec3 m_vMaxVelocity;

	f32 m_fSlowTurnLeft;
	f32 m_fSlowTurnRight;
	f32 m_fFastTurnLeft;
	f32 m_fFastTurnRight;
	f32 m_fAllowDesiredTurning; //is a value between [0...1]

	f32 m_fDesiredLocalLocationLookaheadTime;

	ILINE LMGCapabilities()
	{
		m_bIsValid=0;			// by default not valid
		m_bIsLMG=0;				// 1=LMG / 0=simple asset
		m_bHasStrafingAsset=0;	// 1=has strafing assets    0=don't have, don't care  -1=don't have, don't want at all (prevent)
		m_bHasTurningAsset=0;	// 1=has turning assets    0=don't have, don't care  -1=don't have, don't want at all (prevent)
		m_bHasTurningDistAsset=0;	// 1=has turning assets    0=don't have, don't care  -1=don't have, don't want at all (prevent)
		m_bHasSlopeAsset=0;    // 1=supports uphill/downhill
		m_bHasVelocity=0;	// 1=has parameterized speed    0=don't have, don't care  -1=don't have, don't want at all (prevent)
		m_bHasDistance=0;	// 1=has parameterized speed    0=don't have, don't care  -1=don't have, don't want at all (prevent)
		m_bHasCurving=0;

		m_bpad1=0;
		m_bpad2=0;

		m_BlendType=0;

		m_travelAngleChangeRate = 0.0f;
		m_travelSpeedChangeRate = 0.0f;
		m_turnSpeedChangeRate = 0.0f;
		m_curvingChangeRate = 0.0f;

		m_fSlowDuration=-1.0f;
		m_fFastDuration=-1.0f;

		m_vMinVelocity.Set(0,0,0);
		m_vMaxVelocity.Set(0,0,0);

		m_fSlowTurnLeft=0;
		m_fSlowTurnRight=0;
		m_fFastTurnLeft=0;
		m_fFastTurnRight=0;
		m_fAllowDesiredTurning=0;

		m_fDesiredLocalLocationLookaheadTime = 0.0f;
	}

	ILINE LMGCapabilities operator * (f32 k) const
	{
		LMGCapabilities caps;
		caps.m_fSlowDuration		=	m_fSlowDuration*k;
		caps.m_fFastDuration		=	m_fFastDuration*k;

		caps.m_vMinVelocity		=	m_vMinVelocity*k;
		caps.m_vMaxVelocity		=	m_vMaxVelocity*k;

		caps.m_fFastTurnLeft					=	m_fFastTurnLeft*k;
		caps.m_fFastTurnRight				=	m_fFastTurnRight*k;
		caps.m_fAllowDesiredTurning	=	m_fAllowDesiredTurning*k;
		return caps;
	}
	ILINE LMGCapabilities operator + (const LMGCapabilities& c) const
	{
		LMGCapabilities caps;

		caps.m_fSlowDuration	=	m_fSlowDuration+c.m_fSlowDuration;
		caps.m_fFastDuration	=	m_fFastDuration+c.m_fFastDuration;

		caps.m_vMinVelocity	=	m_vMinVelocity+c.m_vMinVelocity;
		caps.m_vMaxVelocity	=	m_vMaxVelocity+c.m_vMaxVelocity;

		caps.m_fFastTurnLeft					=	m_fFastTurnLeft+c.m_fFastTurnLeft;
		caps.m_fFastTurnRight				=	m_fFastTurnRight+c.m_fFastTurnRight;
		caps.m_fAllowDesiredTurning	=	m_fAllowDesiredTurning+c.m_fAllowDesiredTurning;
		return caps;

	}

	ILINE static LMGCapabilities Merge(const LMGCapabilities& a, const LMGCapabilities& b, float blend)
	{
		LMGCapabilities merged;

		if (a.m_bIsValid && !b.m_bIsValid)
			return a;

		if (b.m_bIsValid && !a.m_bIsValid)
			return b;

		if (!a.m_bIsValid && !b.m_bIsValid)
			return merged;

		merged.m_bIsValid = true;
		merged.m_bIsLMG = a.m_bIsLMG || b.m_bIsLMG;

		#define GETBLEND(flag) (((a.flag*b.flag) < 0) ? -1.0f : ((a.flag) ? ((b.flag) ? blend : 0.0f) : ((b.flag) ? 1.0f : -1.0f)))
		#define BLEND(member, t) { merged.member = LERP(a.member, b.member, t); }
		#define IFBLEND(flag, t) float t = GETBLEND(flag); merged.flag = (t != -1.0f); if (merged.flag)

		IFBLEND(m_bHasStrafingAsset, strafeBlend)
		{
			BLEND(m_travelAngleChangeRate, strafeBlend);
		}
		
		IFBLEND(m_bHasTurningAsset, turnBlend)
		{
			BLEND(m_fFastTurnLeft, turnBlend);
			BLEND(m_fFastTurnRight, turnBlend);
			BLEND(m_fAllowDesiredTurning, turnBlend);
		}

		IFBLEND(m_bHasVelocity, veloBlend)
		{
			BLEND(m_vMinVelocity, veloBlend);
			BLEND(m_vMaxVelocity, veloBlend);
			BLEND(m_travelSpeedChangeRate, veloBlend);
		}

		
		IFBLEND(m_bHasDistance, distBlend)
		{
			BLEND(m_vMinVelocity, distBlend);
			BLEND(m_vMaxVelocity, distBlend);
			BLEND(m_fSlowDuration, distBlend);
			BLEND(m_fFastDuration, distBlend);
		}
		else
		{
			BLEND(m_fSlowDuration, blend);
			BLEND(m_fFastDuration, blend);
		}

		IFBLEND(m_bHasSlopeAsset, slopeBlend)
		{
		}

		merged.m_BlendType = (blend < 0.5f) ? a.m_BlendType : b.m_BlendType;


		return merged;
	}

};

//--------------------------------------------------------------------------------

struct SAnimationSelectionProperties
{
	f32 m_fDurationMin;
	f32 m_fDurationMax;
	f32 m_fStartTravelSpeedMin;
	f32 m_fStartTravelSpeedMax;
	f32 m_fEndTravelSpeedMin;
	f32 m_fEndTravelSpeedMax;
	f32 m_fTravelDistanceMin;
	f32 m_fTravelDistanceMax;
	f32 m_fStartTravelAngleMin; // Relative to StartBodyAngle
	f32 m_fStartTravelAngleMax; // Relative to StartBodyAngle
	f32 m_fEndTravelAngleMin; // Relative to StartBodyAngle
	f32 m_fEndTravelAngleMax; // Relative to StartBodyAngle
	f32 m_fEndBodyAngleMin;  // Relative to StartBodyAngle
	f32 m_fEndBodyAngleMax;  // Relative to StartBodyAngle
	// StartBodyAngle is zero, by definition.
	f32 m_fTravelAngleChangeMin;
	f32 m_fTravelAngleChangeMax;
	f32 m_fEndTravelToBodyAngleMin;
	f32 m_fEndTravelToBodyAngleMax;
	f32 m_fUrgencyMin;
	f32 m_fUrgencyMax;
	bool m_bPredicted; // Indicates this is a fancy animation that relies on prediction and should not be preferred (or used at all) if no prediction is available.
	bool m_bGuarded; // Optimization, indicates that AG pathfinding should apply animation dependent guard on states using this animation.
	bool m_bComplexBodyTurning; // Indicates that the body angle will change either quickly or complex (and should not be clamped to the entity, as much).
	bool m_bComplexTravelPath; // Indicates that the path changes either quickly or complex (and should not be clamped to the entity, as much).
	bool m_bLocomotion;
	float m_fEndBodyAngleThreshold;
	float m_fTravelDistanceThreshold;

//#ifdef _DEBUG
	uint32 DebugCapsCode;
//#endif

	SAnimationSelectionProperties()
	{
		init();
	}

	void init()
	{
//#ifdef _DEBUG
		DebugCapsCode = 0;
//#endif

		m_fDurationMin = 0.0f;
		m_fDurationMax = 0.0f;
		m_fStartTravelSpeedMin = 0.0f;
		m_fStartTravelSpeedMax = 0.0f;
		m_fEndTravelSpeedMin = 0.0f;
		m_fEndTravelSpeedMax = 0.0f;
		m_fTravelDistanceMin = 0.0f;
		m_fTravelDistanceMax = 0.0f;
		m_fStartTravelAngleMin = 0.0f;
		m_fStartTravelAngleMax = 0.0f;
		m_fEndTravelAngleMin = 0.0f;
		m_fEndTravelAngleMax = 0.0f;
		m_fEndBodyAngleMin = 0.0f;
		m_fEndBodyAngleMax = 0.0f;
		m_fTravelAngleChangeMin = 0.0f;
		m_fTravelAngleChangeMax = 0.0f;
		m_fEndTravelToBodyAngleMin = 0.0f;
		m_fEndTravelToBodyAngleMax = 0.0f;
		m_fUrgencyMin = 0.0f;
		m_fUrgencyMax = 0.0f;
		m_bPredicted = false;
		m_bGuarded = false;
		m_bComplexBodyTurning = false;
		m_bComplexTravelPath = false;
		m_bLocomotion = false;
		m_fEndBodyAngleThreshold = 0.0f;
		m_fTravelDistanceThreshold = 0.0f;
	}

	void expand(const SAnimationSelectionProperties* other)
	{
		if (other == NULL)
			return;

		#define EXPAND(name)		{ m_f##name##Min = min(m_f##name##Min, other->m_f##name##Min); m_f##name##Max = max(m_f##name##Max, other->m_f##name##Max); }

//#ifdef _DEBUG
		DebugCapsCode = 0xFFFF;
//#endif

		EXPAND(Urgency);
		EXPAND(Duration);
		EXPAND(StartTravelSpeed);
		EXPAND(EndTravelSpeed);
		EXPAND(TravelDistance);
		EXPAND(StartTravelAngle);
		EXPAND(EndTravelAngle);
		EXPAND(EndBodyAngle);
		EXPAND(TravelAngleChange);
		EXPAND(EndTravelToBodyAngle);
		m_bPredicted = m_bPredicted || other->m_bPredicted;
		m_bGuarded = m_bGuarded || other->m_bGuarded;
		m_bComplexBodyTurning = m_bComplexBodyTurning || other->m_bComplexBodyTurning;
		m_bComplexTravelPath = m_bComplexTravelPath || other->m_bComplexTravelPath;
	}

	void GetMemoryUsage( ICrySizer *pSizer ) const {/*nothing*/}
};

//--------------------------------------------------------------------------------

struct CryAnimationPath
{
	QuatT m_key0;
	QuatT m_key1;
};

struct SAnimRoot
{
	f32 m_NormalizedTimeAbs;
	f32 m_KeyTimeAbs;
	QuatT m_TransRot;

	SAnimRoot()
	{
		m_NormalizedTimeAbs	=	0;
		m_KeyTimeAbs	=	0;
		m_TransRot.SetIdentity();
	};

}_ALIGN(8);






struct AnimEventInstance
{
	f32 m_time;
	uint32 m_nAnimNumberInQueue;
	f32 m_fAnimPriority;
	const char* m_AnimPathName;
	int m_AnimID;
	uint32 m_EventNameLowercaseCRC32;
	const char* m_EventName;
	const char* m_CustomParameter; // Meaning depends on event - sound: sound path, effect: effect name
	const char* m_BonePathName;
	Vec3 m_vOffset;
	Vec3 m_vDir;
		
	AnimEventInstance()
	{
		m_time=0;
		m_nAnimNumberInQueue=0;
		m_fAnimPriority=0;
		m_AnimPathName=0;
		m_AnimID=0;
		m_EventNameLowercaseCRC32=0;
		m_EventName=0;
		m_CustomParameter=0;
		m_BonePathName=0;
		m_vOffset = Vec3(0, 0, 0);
		m_vDir = Vec3(0, 0, 0);
	}
};

//////////////////////////////////////////////////////////////////////////
// This structure describes the parameters used to start an animation
// on a character.
struct CryCharAnimationParams
{
	CryCharAnimationParams( int _nLayerID=0, uint32 _nFlags=0) : m_fTransTime(-1.0f),
		m_fKeyTime(-1.0f), m_fPlaybackSpeed(1.0f),
		m_fAllowMultilayerAnim(1.0f), m_nLayerID( _nLayerID),
		m_nFlags(_nFlags), m_nUserToken(0),
		m_fLayerWeight(1.0f)
	{
		for (int i=0; i<NUM_ANIMATION_USER_DATA_SLOTS; i++)
			m_fUserData[i] = 0.0f;
	}
	// transition time between two animations.
	f32 m_fTransTime;
	// keytime[0-1]. can be used to start a transition animation.
	f32 m_fKeyTime;
	// multiplier for animation-update.
	f32	m_fPlaybackSpeed;
	// if this is '1' then we can play animation on higher layers and they overwrite the channels on lower layers.
	f32	m_fAllowMultilayerAnim;

	// Specify the layer where to start the animation.
	int32 m_nLayerID;
	// every layer can override the previous layer with certain transition weight
	f32 m_fLayerWeight;
	// Combination of flags defined above.
	uint32 m_nFlags;

	// Token specified by the animation calling code for it's own benefit.
	uint32 m_nUserToken;

	// a set of weights that are blended together just like the animation is, for calling code's benefit
	f32 m_fUserData[NUM_ANIMATION_USER_DATA_SLOTS];


	void Serialize(TSerialize ser)
	{
		if (ser.GetSerializationTarget() != eST_Network)
		{
			ser.BeginGroup("CharAnimationParams");
			for (int32 i=0; i<NUM_ANIMATION_USER_DATA_SLOTS; i++)
			{
				string serializeName;
				serializeName.Format("fUserData%i", i);
				ser.Value(serializeName.c_str(), m_fUserData[i]);
			}

			ser.Value("fTransTime", m_fTransTime);
			ser.Value("fKeyTime", m_fKeyTime);
			ser.Value("fPlaybackSpeed", m_fPlaybackSpeed);
			ser.Value("fAllowMultilayerAnim", m_fAllowMultilayerAnim);
			ser.Value("nLayerID", m_nLayerID);
			ser.Value("nUserToken", m_nUserToken);
			ser.Value("nFlags", m_nFlags);
			ser.EndGroup();
		}
	}

} _ALIGN(8);

struct MotionParamBlendSpace
{
	f32 m_fAssetBlend;
	f32 m_fProceduralOffset;
	f32 m_fProceduralScale;
	f32 m_fAllowProceduralTurn;

	MotionParamBlendSpace()
	{
		m_fAssetBlend				  = 0.5f;
		m_fProceduralOffset		= 0.0f;
		m_fProceduralScale		= 1.0f;
		m_fAllowProceduralTurn = 0.0f;
	}

} _ALIGN(16);

struct MotionParam
{
	MotionParamDesc desc;
	MotionParamBlendSpace blendspace;
	bool initialized;
	f32 value;
	f32 delta;

	MotionParam()
	{
		initialized = false;
		value = 0.0f;
		delta = 0.0f;
	}
	void Serialize(TSerialize ser)
	{
		if (ser.GetSerializationTarget() != eST_Network)
		{
			ser.BeginGroup("MotionParam");
			ser.Value("initialized", initialized);
			ser.Value("value", value);
			ser.Value("delta", delta);
			ser.EndGroup();
		}
	}

} _ALIGN(64);

ILINE bool operator==(const MotionParam& lhs, const MotionParam& rhs)
{
	// doesn't check desc or blendspace, since they're not serialized
	return lhs.initialized == rhs.initialized
		&& lhs.value == rhs.value
		&& lhs.delta == rhs.delta;
}

ILINE bool operator!=(const MotionParam& lhs, const MotionParam& rhs)
{
	return !(lhs == rhs);
}

struct SParametric
{
	int16		m_nParametricID;												//if >=0 then this is a "locomotion group"
	int16		m_numAnims;											//number of used animations per locomotion group

	int16		m_nAnimID[MAX_LMG_ANIMS];
	int16		m_nSegmentCounter[MAX_LMG_ANIMS];
	f32			m_fBlendWeight[MAX_LMG_ANIMS];		//percentage blend-value for this motion

	OldBlendSpace	m_BlendSpace;								//interpolation weights for blend-space
	float m_fDesiredLocalLocationLookaheadTime;
	uint32 m_nStopIndex;
	MotionParam m_params[eMotionParamID_COUNT];

	SParametric()
	{
		m_nParametricID	= -3;
		m_numAnims			= 0;
		for (uint32 i=0; i<MAX_LMG_ANIMS; i++)
		{
			m_nAnimID[i]				    = -7;
			m_nSegmentCounter[i]    = 0;
			m_fBlendWeight[i]	 	    = 0.0f;	 
		}

		m_nStopIndex=0;
		m_fDesiredLocalLocationLookaheadTime = 0.0f;
	}

	void Serialize(TSerialize ser)
	{
		if (ser.GetSerializationTarget() != eST_Network)
		{
			ser.BeginGroup("SParametric");

			ser.BeginGroup("Params");
			for (int32 i=0; i<eMotionParamID_COUNT; i++)
			{
				string serializeName;
				serializeName.Format("motionParams%i", i);
				ser.ValueWithDefault(serializeName.c_str(), m_params[i], MotionParam());
			}
			ser.EndGroup();

			ser.Value("nParametricID", m_nParametricID);
			ser.Value("numAnims", m_numAnims);
			for (int32 i=0; i<m_numAnims; i++)
			{
				ser.BeginGroup("ID");
				ser.Value("nAnimIDs", m_nAnimID[i]);
				ser.Value("nSegmentCounter", m_nSegmentCounter[i]);
				ser.EndGroup();
			}

			ser.Value("m_fDesiredLocalLocationLookaheadTime", m_fDesiredLocalLocationLookaheadTime);

			ser.EndGroup();
		}
	}

} _ALIGN(16);


struct CAnimation
{
	SParametric *m_Parametric;
	int16 m_nAnimDirID0;								
	int16 m_nAnimDirID1;				

	int16		m_nAnimID;
	int16		m_nSegmentCounter;

	f32			m_fAnimTimePrev;        //this is a percentage value between 0-1
	f32			m_fAnimTime;						//this is a percentage value between 0-1
	f32			m_fTransitionPriority;	//motion priority: a value of '1' is overwriting all other motion in the queue
	f32			m_fTransitionWeight;		//this is the real percentage value for all active motions in the transition queue
	f32			m_fCurrentPlaybackSpeed; //here only for debugging
	f32			m_fCurrentDuration;
	f32			m_fCurrentDeltaTime;

	uint16  m_nRepeatCount;
	uint16  m_nLoopCount;
	uint16  m_nKeyPassed;
	uint16  m_bActivated;				//this anim is currently playing

	uint16  m_bRemoveFromQueue; //this anim is not need any more in the queue
	uint8		m_bTWFlag;
	uint8		m_bEndOfCycle;

	uint16  m_nSegCounter;
	uint16  m_nSegHighest;

	CryCharAnimationParams m_AnimParams;
		
	CAnimation()
	{
		m_nAnimDirID0=-4;								
		m_nAnimDirID1=-4;								

		m_nAnimID = 0;
		m_nSegmentCounter				=	0;

		m_fAnimTimePrev					= 0.0f;
		m_fAnimTime							= 0.0f;

		m_fTransitionPriority		= 0.0f;
		m_fTransitionWeight			= -1.0f;
		m_fCurrentPlaybackSpeed	= 0.0f;
		m_fCurrentDuration			= -1.0f;
		m_fCurrentDeltaTime	    = -1.0f;

		m_nRepeatCount					= 0;
		m_nLoopCount						= 0;
		m_nKeyPassed    				= 0;
		m_bActivated						= false;

		m_bRemoveFromQueue			=	false;
		m_bTWFlag								=	false;
		m_bEndOfCycle						=	false;

		m_nSegCounter						=	0;
		m_nSegHighest           = 0xffff;

		m_AnimParams.m_nLayerID	=	0;
		m_AnimParams.m_nFlags		=	0;

		m_Parametric = NULL;
	};

	void Serialize(TSerialize ser)
	{
		if (ser.GetSerializationTarget() != eST_Network)
		{
			ser.BeginGroup("CAnimation");

			ser.Value("nAnimID", m_nAnimID);

			ser.ValueWithDefault("nAnimDirID0", m_nAnimDirID0, (int16)-4);
			ser.ValueWithDefault("nAnimDirID1", m_nAnimDirID1, (int16)-4);

			ser.Value("fAnimTimePrev", m_fAnimTimePrev);
			ser.Value("fAnimTime", m_fAnimTime);
			
			ser.Value("fTransitionPriority", m_fTransitionPriority);
			ser.Value("fTransitionWeight", m_fTransitionWeight);
			ser.Value("fCurrentPlaybackSpeed", m_fCurrentPlaybackSpeed);
			ser.Value("fCurrentDuration", m_fCurrentDuration);
			ser.Value("fCurrentDeltaTime", m_fCurrentDeltaTime);

			ser.Value("nRepeatCount", m_nRepeatCount);
			ser.Value("nLoopCount", m_nLoopCount);
			ser.Value("nKeyPassed", m_nKeyPassed);
			ser.Value("bActivated", m_bActivated);

			ser.Value("bRemoveFromQueue", m_bRemoveFromQueue);
			ser.Value("m_bTWFlag",m_bTWFlag);
			ser.Value("m_bEndOfCycle",m_bEndOfCycle);

			ser.Value("nSegCounter", m_nSegCounter);
			ser.ValueWithDefault("nSegHighest", m_nSegHighest, (uint16)1);
			ser.EndGroup();

			//if (m_Parametric)
			//{
			//	ser.BeginGroup("SParametric");
			//	m_Parametric->Serialize(ser);
			//	ser.EndGroup();
			//}

			ser.BeginGroup("AnimParams");
			m_AnimParams.Serialize(ser);
			ser.EndGroup();
		}
	}

	void GetMemoryUsage(ICrySizer *pSizer ) const{}

} _ALIGN(16);



struct Joint
{
	int32 m_idxParent;
	const char* m_strJointName;
};

struct AimPoseDesc
{
	const char* animName;
	int frameNum;
	const char* baseAimAnimName;
};

#endif
